package jsu.weizixuan.likesystem.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.servlet.http.HttpServletRequest;
import jsu.weizixuan.likesystem.constant.RedisLuaScriptConstant;
import jsu.weizixuan.likesystem.constant.ThumbConstant;
import jsu.weizixuan.likesystem.mapper.ThumbMapper;
import jsu.weizixuan.likesystem.model.enums.LuaStatusEnum;
import jsu.weizixuan.likesystem.model.pojo.DoThumbRequest;
import jsu.weizixuan.likesystem.model.pojo.Thumb;
import jsu.weizixuan.likesystem.model.pojo.User;
import jsu.weizixuan.likesystem.service.ThumbService;
import jsu.weizixuan.likesystem.service.UserService;
import jsu.weizixuan.likesystem.util.RedisKeyUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Arrays;

@Service("thumbServiceRedis")
@Slf4j
@RequiredArgsConstructor
public class ThumbServiceRedisImpl extends ServiceImpl<ThumbMapper, Thumb> implements ThumbService {

    private final UserService userService;

    private final RedisTemplate<String, Object> redisTemplate;

    /**
     * 判断用户是否已点赞
     *
     * @param blogId
     * @param userId
     * @return
     */
    @Override
    public Boolean hasThumb(Long blogId, Long userId) {
        return redisTemplate.opsForHash().hasKey(ThumbConstant.USER_THUMB_KEY_PREFIX + userId, blogId.toString());
    }

    @Override
    public Long getThumbCount(Long blogId, HttpServletRequest request) {
        return 0L;
    }

    /**
     * 版本二：
     * 通过lua脚本实现原子性操作，保证点赞状态和临时记录要么同时存在，要么同时不存在，不会因为系统宕机而导致数据不一致
     */
    /**
     * 点赞
     *
     * @param doThumbRequest
     * @param request
     * @return
     */
    @Override
    public Boolean doThumb(DoThumbRequest doThumbRequest, HttpServletRequest request) {
        if (doThumbRequest == null || doThumbRequest.getBlogId() == null) {
            throw new RuntimeException("参数错误");
        }
        User loginUser = userService.getLoginUser(request);
        Long blogId = doThumbRequest.getBlogId();

        String timeSlice = getTimeSlice();
        // 生成临时点赞记录的key
        String tempThumbKey = RedisKeyUtil.getTempThumbKey(timeSlice);
        String userThumbKey = RedisKeyUtil.getUserThumbKey(loginUser.getId());

        // 执行lua脚本 1.检查用户是否点赞，2.记录点赞状态，3.写入临时点赞记录，等待定时同步任务
        long result = redisTemplate.execute(
                RedisLuaScriptConstant.THUMB_SCRIPT,
                Arrays.asList(tempThumbKey, userThumbKey),
                loginUser.getId(),
                blogId
        );

        if (LuaStatusEnum.FAIL.getValue() == result) {
            throw new RuntimeException("用户已点赞");
        }

        // 更新成功
        return LuaStatusEnum.SUCCESS.getValue() == result;
    }

    /**
     * 取消点赞
     *
     * @param doThumbRequest
     * @param request
     * @return
     */
    @Override
    public Boolean undoThumb(DoThumbRequest doThumbRequest, HttpServletRequest request) {
        if (doThumbRequest == null || doThumbRequest.getBlogId() == null) {
            throw new RuntimeException("参数错误");
        }
        User loginUser = userService.getLoginUser(request);
        Long blogId = doThumbRequest.getBlogId();

        String timeSlice = getTimeSlice();
        // 生成临时点赞记录的key
        String tempThumbKey = RedisKeyUtil.getTempThumbKey(timeSlice);
        String userThumbKey = RedisKeyUtil.getUserThumbKey(loginUser.getId());

        // 执行lua脚本 1.检查用户是否点赞，2.记录点赞状态，3.写入临时点赞记录，等待定时同步任务
        long result = redisTemplate.execute(
                RedisLuaScriptConstant.UNTHUMB_SCRIPT,
                Arrays.asList(tempThumbKey, userThumbKey),
                loginUser.getId(),
                blogId
        );

        if (LuaStatusEnum.FAIL.getValue() == result) {
            throw new RuntimeException("用户未点赞");
        }

        // 更新成功
        return LuaStatusEnum.SUCCESS.getValue() == result;

    }

    /**
     * 获取当前时间前最近的的整数时间
     * @return
     */
    private String getTimeSlice() {
        DateTime date = DateUtil.date();
        return DateUtil.format(date, "HH:mm:") + (DateUtil.second(date) / 10) * 10;
    }

}
